﻿//Srinivasan

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace Tzync
{
    /******************************************************************************************************************/
    /* Partial Class to Analyze the Guest System's files and its MetaData and find Conflicting/Non-Conflicting Updates */
    /******************************************************************************************************************/

    partial class Analyze
    {

        //Description     : Given a list of folders and corresponding MetaData entry TreeNodes, this function computes
        // the differences between them by recursively calling findDiff() method.                       

        private void FindFolderDifference(DirectoryInfo[] sysDirectories, List<int> directoryChilds, int nodeParent)
        {            
            Pair<DirectionType, OperationType> folderStatus = new Pair<DirectionType, OperationType>();
            int sysSize = sysDirectories.Count(), partnerSize = directoryChilds.Count(), partnerIndex;
            List<String> nodeDirectoryNames = new List<string>();
            bool[] partnerFolderVisited = new bool[directoryChilds.Count()];            
            int vA_f, vA_s, vB_f, vB_s;

            for (int i = 0; i < partnerSize; i++)
            {
                partnerFolderVisited[i] = false;
                nodeDirectoryNames.Add(arrNode[directoryChilds[i]].GetName());
            }

            for (int i = 0; i < sysSize; i++)
            {
                partnerIndex = nodeDirectoryNames.IndexOf(sysDirectories[i].Name);                                 
                               
                if (partnerIndex >= 0 && directoryChilds[partnerIndex] < arrNode.Count())
                {
                    vA_f = arrNode[directoryChilds[partnerIndex]].GetVersionHost().First;
                    vA_s = arrNode[directoryChilds[partnerIndex]].GetVersionHost().Second;
                    vB_f = arrNode[directoryChilds[partnerIndex]].GetVersionGuest().First;
                    vB_s = arrNode[directoryChilds[partnerIndex]].GetVersionGuest().Second;
                    partnerFolderVisited[partnerIndex] = true;                    

                    //If folder is found in system, the following region checks for appropriate set of differences                    

                    if (systemName == SystemType.Host)
                    {
                        arrNode[directoryChilds[partnerIndex]].SetFullPathHost(sysDirectories[i].FullName);

                        Analyze_Folder(sysDirectories[i], directoryChilds, partnerIndex, vA_f, vA_s, vB_f, vB_s, arrNode[directoryChilds[partnerIndex]].GetSyncHost());
                        FindDiff(sysDirectories[i], arrNode[directoryChilds[partnerIndex]]);
                    }

                    else if (systemName == SystemType.Guest)
                    {
                        arrNode[directoryChilds[partnerIndex]].SetFullPathGuest(sysDirectories[i].FullName);

                        //If this is the first time in System B
                        if (firstSyncGuest == true)
                        {
                            folderStatus.First = DirectionType.None;
                            folderStatus.Second = OperationType.None;

                            arrNode[directoryChilds[partnerIndex]].GetVersionGuest().First = arrNode[directoryChilds[partnerIndex]].GetVersionHost().First;
                            arrNode[directoryChilds[partnerIndex]].GetVersionGuest().Second = arrNode[directoryChilds[partnerIndex]].GetVersionHost().Second;
                            FindDiff(sysDirectories[i], arrNode[directoryChilds[partnerIndex]]);
                            continue;
                        }

                        Analyze_Folder(sysDirectories[i], directoryChilds, partnerIndex, vB_s, vB_f, vA_s, vA_f, arrNode[directoryChilds[partnerIndex]].GetSyncGuest());
                        FindDiff(sysDirectories[i], arrNode[directoryChilds[partnerIndex]]);
                    }                    
                }

                //Non-Conflicting Creation in Current system

                if (partnerIndex < 0)
                {
                    TreeNode N;

                    folderStatus = new Pair<DirectionType, OperationType>();
                    folderStatus.First = DirectionType.SystemToHD; 
                    folderStatus.Second = OperationType.Creation;

                    if (filter.IsValidFolder(sysDirectories[i].FullName))
                    {
                        N = treeHandler.folderUpdateArrNode(sysDirectories[i], nodeParent);
                        AddDifference(new Difference(sysDirectories[i], N, folderStatus));
                        FindDiff(sysDirectories[i], N);
                        folderStatus = new Pair<DirectionType, OperationType>();
                    }                    
                }               
            }

            //If file is not found in Current System, but a TreeNode for the file exists
            //Check for (Deletions in Current System)/(Creations in Partner System)

            for (int i = 0; i < partnerSize; i++)
            {
                if (directoryChilds[i] >= arrNode.Count()) continue;

                vA_f = arrNode[directoryChilds[i]].GetVersionHost().First;
                vA_s = arrNode[directoryChilds[i]].GetVersionHost().Second;
                vB_f = arrNode[directoryChilds[i]].GetVersionGuest().First;
                vB_s = arrNode[directoryChilds[i]].GetVersionGuest().Second;

                //If the file is not found in Current system, the following function checks for appropriate set of differences 

                if (partnerFolderVisited[i] == false && directoryChilds[i] != -1 && systemName == SystemType.Host)
                {
                    Analyze_FolderTreeNode(directoryChilds, nodeParent, vA_f, vA_s, vB_f, vB_s, i, arrNode[directoryChilds[i]].GetFullPathHost());
                }

                else if (partnerFolderVisited[i] == false && directoryChilds[i] != -1 && systemName == SystemType.Guest)
                {
                    Analyze_FolderTreeNode(directoryChilds, nodeParent, vB_s, vB_f, vA_s, vA_f, i, arrNode[directoryChilds[i]].GetFullPathGuest());
                }                
            }
        }

        //Analyzes a single folder by recursively calling FindDiff() method with itself as root Directory

        private void Analyze_Folder(DirectoryInfo sysDirectory, List<int> directoryChilds, int partnerIndex, int SystemSystem, int SystemPartner, int PartnerSystem, int PartnerPartner, String storedTime)
        {            
            String dT = Utility.ParseDateTime(sysDirectory.LastWriteTime);
            
            Pair<DirectionType, OperationType> folderStatus = new Pair<DirectionType, OperationType>();

            if (PartnerSystem == 0 && PartnerPartner == 1 && SystemSystem == 0 && SystemPartner == 0)
            {
                folderStatus.First = DirectionType.HDToSystem;
                folderStatus.Second = OperationType.CreationCreationConflict;
                AddDifference(new Difference(sysDirectory, arrNode[directoryChilds[partnerIndex]], folderStatus));
            }

            else if (PartnerSystem == 0 && PartnerPartner == -1)
            {
                folderStatus.First = DirectionType.HDToSystem;
                folderStatus.Second = OperationType.Deletion;
                AddDifference(new Difference(sysDirectory, arrNode[directoryChilds[partnerIndex]], folderStatus));
            }                        
        }

        //Analyzes a single TreeNode for a folder not in system and recursively marks its contents as Created/Deleted
        //by calling RecurseDirectoryNode

        private void Analyze_FolderTreeNode(List<int> directoryChilds, int nodeParent, int SystemSystem, int SystemPartner, int PartnerSystem, int PartnerPartner, int i, String folderAddress)
        {
            Pair<DirectionType, OperationType> f = new Pair<DirectionType, OperationType>();

            //Non-Conflicting Creation in the Partner System

            if (SystemSystem == 0 && SystemPartner == 0)
            {
                String newAddress;
                f.First = DirectionType.HDToSystem; f.Second = OperationType.Creation;

                if (systemName == SystemType.Host)
                {
                    newAddress = Path.Combine(arrNode[nodeParent].GetFullPathHost(), arrNode[directoryChilds[i]].GetName());
                    arrNode[directoryChilds[i]].SetFullPathHost(newAddress);
                    AddDifference(new Difference(new DirectoryInfo(arrNode[directoryChilds[i]].GetFullPathGuest()), arrNode[directoryChilds[i]], f));
                }
                else if (systemName == SystemType.Guest)
                {
                    newAddress = Path.Combine(arrNode[nodeParent].GetFullPathGuest(), arrNode[directoryChilds[i]].GetName());
                    arrNode[directoryChilds[i]].SetFullPathGuest(newAddress);
                    AddDifference(new Difference(new DirectoryInfo(arrNode[directoryChilds[i]].GetFullPathHost()), arrNode[directoryChilds[i]], f));
                }
                RecurseDirectoryNode(arrNode[directoryChilds[i]], f, 0);
            }

            //Conflicting Deletion on both sides

            else if (PartnerSystem == 0 && PartnerPartner == -1)
            {
                f.First = DirectionType.HDToSystem;
                f.Second = OperationType.DeletionDeletionConflict;
                AddDifference(new Difference(new FileInfo(@folderAddress), arrNode[directoryChilds[i]], f));
                RecurseDirectoryNode(arrNode[directoryChilds[i]], f, 0);
            }

            //Non-Conflicting Deletion in Current System

            else if (!(SystemSystem == -1 && SystemPartner == 0))
            {
                f.Second = OperationType.Deletion;
                f.First = DirectionType.SystemToHD;

                if (systemName == SystemType.Host && filter.IsValidFolder(arrNode[directoryChilds[i]].GetFullPathHost()))
                    AddDifference(new Difference(new DirectoryInfo(folderAddress), arrNode[directoryChilds[i]], f));
                if (systemName == SystemType.Guest && filter.IsValidFolder(arrNode[directoryChilds[i]].GetFullPathGuest()))
                    AddDifference(new Difference(new DirectoryInfo(folderAddress), arrNode[directoryChilds[i]], f));

                RecurseDirectoryNode(arrNode[directoryChilds[i]], f, 0);
            }

        }

        //Description     : In cases of Deletion in Current system or creation in partner system, where the Folder/Files
        //do not exist, this function recurses through the corresponding TreeNodes and marks them as Deleted/Created
        //appropriately

        public void RecurseDirectoryNode(TreeNode N, Pair<DirectionType, OperationType> f, int systemID)
        {
            List<int> fileChilds, folderChilds;
            String newAddress;
            int nodeParent = N.GetId();

            fileChilds = treeHandler.getFileChilds(N);
            folderChilds = treeHandler.getFolderChilds(N);            

            if (systemName.CompareTo(SystemType.Host) == 0)
            {
                for (int j = 0; j < fileChilds.Count(); j++)
                {
                    String fileName = arrNode[fileChilds[j]].GetName();
                    newAddress = Path.Combine(arrNode[nodeParent].GetFullPathHost(), arrNode[fileChilds[j]].GetName());
                    arrNode[fileChilds[j]].SetFullPathHost(newAddress);

                    if (f.First == DirectionType.SystemToHD)
                    {
                        if (!filter.IsValidFile(fileName, newAddress))
                            continue;
                    }

                    if (systemID == 0 && f.Second!=OperationType.None)
                    {                        
                        AddDifference(new Difference(new FileInfo(@arrNode[fileChilds[j]].GetFullPathHost()), arrNode[fileChilds[j]], f));
                    }
                    else if (f.Second != OperationType.None)
                    {                        
                        AddDifference(new Difference(new FileInfo(@arrNode[fileChilds[j]].GetFullPathGuest()), arrNode[fileChilds[j]], f));
                    }
                }

                for (int j = 0; j < folderChilds.Count(); j++)
                {
                    newAddress = Path.Combine(arrNode[nodeParent].GetFullPathHost(), arrNode[folderChilds[j]].GetName());
                    arrNode[folderChilds[j]].SetFullPathHost(newAddress);
                    if (systemID == 0 && f.Second!=OperationType.None)
                        AddDifference(new Difference(new DirectoryInfo(arrNode[folderChilds[j]].GetFullPathHost()), arrNode[folderChilds[j]], f));
                    else if (f.Second != OperationType.None)
                        AddDifference(new Difference(new DirectoryInfo(arrNode[folderChilds[j]].GetFullPathGuest()), arrNode[folderChilds[j]], f));

                    RecurseDirectoryNode(arrNode[folderChilds[j]], f, systemID);    //Recurse here
                }
            }

            else if (systemName.CompareTo(SystemType.Guest) == 0)
            {
                for (int j = 0; j < fileChilds.Count(); j++)
                {
                    String fileName = arrNode[fileChilds[j]].GetName();
                    newAddress = Path.Combine(arrNode[nodeParent].GetFullPathGuest(), arrNode[fileChilds[j]].GetName());
                    arrNode[fileChilds[j]].SetFullPathGuest(newAddress);                    

                    if (systemID == 0 && f.Second != OperationType.None && filter.IsValidFile(fileName, newAddress))
                    {
                        AddDifference(new Difference(new FileInfo(@arrNode[fileChilds[j]].GetFullPathHost()), arrNode[fileChilds[j]], f));
                    }
                    else if (f.Second != OperationType.None && filter.IsValidFile(fileName, newAddress))
                    {
                        AddDifference(new Difference(new FileInfo(@arrNode[fileChilds[j]].GetFullPathGuest()), arrNode[fileChilds[j]], f));
                    }
                }

                for (int j = 0; j < folderChilds.Count(); j++)
                {
                    newAddress = Path.Combine(arrNode[nodeParent].GetFullPathGuest(), arrNode[folderChilds[j]].GetName());
                    arrNode[folderChilds[j]].SetFullPathGuest(newAddress);
                    if (systemID == 0 && f.Second != OperationType.None)
                        AddDifference(new Difference(new DirectoryInfo(arrNode[folderChilds[j]].GetFullPathHost()), arrNode[folderChilds[j]], f));
                    else if (f.Second != OperationType.None)
                        AddDifference(new Difference(new DirectoryInfo(arrNode[folderChilds[j]].GetFullPathGuest()), arrNode[folderChilds[j]], f));

                    RecurseDirectoryNode(arrNode[folderChilds[j]], f, systemID);    //Recurse here
                }
            }
        }
        
    }

    /******************************/
    /* Partial Class Analyze Ends */
    /******************************/
}
